package com.spzx.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.utils.bean.BeanUtils;
import com.spzx.common.core.web.domain.BaseEntity;
import com.spzx.common.redis.cache.GuiguCache;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.product.api.domain.SkuPrice;
import com.spzx.product.api.domain.SkuQuery;
import com.spzx.product.api.domain.Product;
import com.spzx.product.api.domain.vo.SkuStockVo;
import com.spzx.product.api.domain.ProductDetails;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.domain.SkuStock;
import com.spzx.product.mapper.ProductDetailsMapper;
import com.spzx.product.mapper.ProductMapper;
import com.spzx.product.mapper.ProductSkuMapper;
import com.spzx.product.mapper.SkuStockMapper;
import com.spzx.product.service.ProductService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.product.service.ProductSkuService;
import com.spzx.product.service.SkuStockService;
import jakarta.annotation.Resource;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品 服务实现类
 * </p>
 *
 * @author Haoran Sun
 * @since 2024-07-15
 */
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

    @Resource
    private ProductMapper productMapper;
    @Resource
    private ProductDetailsMapper productDetailsMapper;
    @Resource
    private ProductSkuMapper productSkuMapper;
    @Resource
    private SkuStockMapper skuStockMapper;
    @Resource
    private ProductSkuService productSkuService;
    @Resource
    private SkuStockService skuStockService;
    @Resource
    private RedissonClient redissonClient;


    @Override
    public List<Product> listProductByQuery(Product product) {
        return productMapper.listProductByQuery(product);
    }

    @Override
    public int updateAuditStatus(Long id, Byte auditStatus) {
        return productMapper.updateById(Product.builder()
                .id(id)
                .auditStatus(auditStatus)
                .auditMessage(auditStatus == 1 ? "审批通过" : "审批不通过")
                .build());
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertProduct(Product product) {
        // 1.保存商品
        product.setStatus((byte) 0);
        product.setAuditStatus((byte) 0);
        int result = productMapper.insert(product);
        // 2.保存商品详情
        result += productDetailsMapper.insert(ProductDetails.builder()
                .productId(product.getId())
                .imageUrls(String.join(",", product.getDetailImagesUrlList()))
                .build());
        List<ProductSku> productSkuList = product.getProductSkuList();
        if (productSkuList == null) throw new ServiceException("商品的sku不能为空");
        for (int i = 0; i < productSkuList.size(); i++) {
            ProductSku productSku = productSkuList.get(i);
            // 3.保存商品sku
            productSku.setProductId(product.getId());
            // skuCode
            productSku.setSkuCode(product.getId() + "_" + i);
            productSku.setSkuName(product.getName() + " " + productSku.getSkuSpec());
            result += productSkuMapper.insert(productSku);
            // 4.保存商品sku库存
            result += skuStockMapper.insert(SkuStock.builder()
                    .skuId(productSku.getId())
                    .totalNum(productSku.getStockNum())
                    .availableNum(productSku.getStockNum())
                    .lockNum(0)
                    .saleNum(0)
                    .status((byte) 0)
                    .build());
        }
        return result;
    }

    @Override
    public int updateProduct(Product product) {
        int result = 0;
        //先删除缓存
        deleteCache(product.getId());
        //1、修改商品信息
        //设置商品状态 为初始状态
        product.setStatus((byte) 0);
        //设置审核状态 为初始状态
        product.setAuditStatus((byte) 0);
        result += productMapper.updateById(product);
        //2、修改商品详情
        result += productDetailsMapper.updateById(ProductDetails.builder()
                .productId(product.getId())
                .imageUrls(String.join(",", product.getDetailImagesUrlList()))
                .build());
        //获取sku列表
        List<ProductSku> productSkuList = product.getProductSkuList();
        //判断sku列表是否为空
        if (productSkuList == null) throw new ServiceException("商品的sku不能为空");
        for (ProductSku productSku : productSkuList) {
            //3、修改商品sku
            //productName发生变化 需要重新设置skuName
            productSku.setSkuName(product.getName() + " " + productSku.getSkuSpec());
            result += productSkuMapper.updateById(productSku);
            //4、修改商品库存
            SkuStock skuStock = skuStockMapper.selectOne(
                    new LambdaQueryWrapper<SkuStock>()
                            .eq(SkuStock::getSkuId, productSku.getId())
                            .select(SkuStock::getId, SkuStock::getLockNum));
            //设置总库存
            skuStock.setTotalNum(productSku.getStockNum());
            //设置可用库存
            skuStock.setAvailableNum(productSku.getStockNum() - skuStock.getLockNum());
            skuStock.setStatus((byte) 0);
            result += skuStockMapper.updateById(skuStock);

        }
        return result;
    }

    private void deleteCache(Long id){
        String productCacheKey = "product:product:" + id;
        redissonClient.getBucket(productCacheKey).delete();
        String productDetailsCacheKey = "product:productDetails:" + id;
        redissonClient.getBucket(productDetailsCacheKey).delete();
        String skuSpecValueCacheKey = "product:skuSpecValue:" + id;
        redissonClient.getBucket(skuSpecValueCacheKey).delete();
        List<ProductSku> productSkus = productSkuMapper.selectList(new LambdaQueryWrapper<ProductSku>()
                .eq(ProductSku::getProductId, id)
                .select(ProductSku::getId));
        productSkus.forEach(productSku -> {
            String productSkuCacheKey = "product:productSku:" + productSku.getId();
            redissonClient.getBucket(productSkuCacheKey).delete();
            String skuStockCacheKey = "product:skuStock:" + productSku.getId();
            redissonClient.getBucket(skuStockCacheKey).delete();
            String skuPriceCacheKey = "product:skuPrice:" + productSku.getId();
            redissonClient.getBucket(skuPriceCacheKey).delete();
        });
    }

    @Override
    public int deleteProductByIds(List<Long> ids) {
        // 1.删除商品信息
        int result = productMapper.deleteBatchIds(ids);
        // 2.删除商品详情
        result += productDetailsMapper.delete(
                new LambdaQueryWrapper<ProductDetails>()
                        .in(ProductDetails::getProductId, ids));
        // 3、删除商品sku
        List<Long> productSkusIds = productSkuMapper.selectList(
                new LambdaQueryWrapper<ProductSku>()
                        .in(ProductSku::getProductId, ids)
                        .select(ProductSku::getId)).stream().map(ProductSku::getId).toList();
        result += productSkuMapper.deleteBatchIds(productSkusIds);
        // 4、删除库存
        result += skuStockMapper.delete(
                new LambdaQueryWrapper<SkuStock>()
                        .in(SkuStock::getSkuId, productSkusIds));
        return result;
    }

    @Override
    public Product getInfoById(Long id) {
        Product product = productMapper.selectOne(
                new LambdaQueryWrapper<Product>()
                        .eq(Product::getId, id)
                        .select(Product::getId,
                                Product::getName,
                                Product::getSliderUrls,
                                Product::getUnitName,
                                Product::getSpecValue,
                                Product::getCategory1Id,
                                Product::getCategory2Id,
                                Product::getCategory3Id,
                                Product::getBrandId));
        //设置详情图片列表
        product.setDetailImagesUrlList(
                Arrays.stream(productDetailsMapper
                                .selectOne(
                                        new LambdaQueryWrapper<ProductDetails>()
                                                .eq(ProductDetails::getProductId, id)
                                                .select(ProductDetails::getImageUrls)
                                ).getImageUrls()
                                .split(",")
                        )
                        .toList());
        //设置商品sku列表
        List<ProductSku> productSkus = productSkuMapper.selectList(
                new LambdaQueryWrapper<ProductSku>()
                        .eq(ProductSku::getProductId, id)
                        .select(ProductSku::getId,
                                ProductSku::getSkuSpec,
                                ProductSku::getSalePrice,
                                ProductSku::getMarketPrice,
                                ProductSku::getCostPrice,
                                ProductSku::getVolume,
                                ProductSku::getWeight));
        //skuId
        List<Long> productSkuIds = productSkus.stream().map(ProductSku::getId).toList();
        //查询库存总量
        List<SkuStock> skuStocks = skuStockMapper.selectList(
                new LambdaQueryWrapper<SkuStock>()
                        .in(SkuStock::getSkuId, productSkuIds)
                        .select(SkuStock::getSkuId, SkuStock::getTotalNum));
        //将库存总量封装为map数据
        Map<Long, Integer> map = skuStocks
                .stream()
                .collect(Collectors.toMap(SkuStock::getSkuId, SkuStock::getTotalNum));
        //设置sku的库存总量
        productSkus.forEach(productSku -> productSku.setStockNum(map.get(productSku.getId())));
        //设置sku列表
        product.setProductSkuList(productSkus);
        return product;
    }

    @Override
    public List<ProductSku> getTopSale() {

        return productMapper.getTopSale();
    }

    @Override
    public List<ProductSku> selectProductSkuList(SkuQuery skuQuery) {
        return productSkuMapper.selectProductSkuList(skuQuery);
    }

    @Override
    @GuiguCache(prefix = "product:productSku:")
    public ProductSku getProductSku(Long skuId) {
        return productSkuMapper.selectById(skuId);
    }

    @Override
    @GuiguCache(prefix = "product:product:")
    public Product getProduct(Long id) {
        return productMapper.selectById(id);
    }

    @Override
    @GuiguCache(prefix = "product:skuPrice:")
    public SkuPrice getSkuPrice(Long skuId) {
        ProductSku productSku = productSkuMapper.selectOne(new LambdaQueryWrapper<ProductSku>()
                .eq(ProductSku::getId, skuId)
                .select(ProductSku::getSalePrice,
                        ProductSku::getMarketPrice));
        return SkuPrice.builder()
                .marketPrice(productSku.getMarketPrice())
                .salePrice(productSku.getSalePrice())
                .skuId(skuId)
                .build();
    }

    @Override
    @GuiguCache(prefix = "product:productDetails:")
    public ProductDetails getProductDetails(Long id) {
        return productDetailsMapper.selectOne(
                new LambdaQueryWrapper<ProductDetails>()
                        .eq(ProductDetails::getProductId, id)
                        .select(ProductDetails::getImageUrls));
    }

    @Override
    @GuiguCache(prefix = "product:skuSpecValue:")
    public Map<String, Long> getSkuSpecValue(Long id) {
        return productSkuMapper.selectList(new LambdaQueryWrapper<ProductSku>()
                .eq(ProductSku::getProductId, id)
                .select(ProductSku::getSkuSpec, ProductSku::getId)
        ).stream().collect(Collectors.toMap(
                ProductSku::getSkuSpec,
                BaseEntity::getId
        ));
    }

    @Override
    @GuiguCache(prefix = "product:skuStock:")
    public SkuStockVo getSkuStock(Long skuId) {
        SkuStock skuStock = skuStockMapper.selectOne(new LambdaQueryWrapper<SkuStock>()
                .eq(SkuStock::getSkuId, skuId));
        SkuStockVo skuStockVo = new SkuStockVo();
        BeanUtils.copyProperties(skuStock, skuStockVo);
        return skuStockVo;
    }

    @Override
    public List<SkuPrice> getSkuPriceList(List<Long> skuIdList) {
        if (skuIdList.isEmpty()) {
            return Collections.emptyList();
        }
        return productSkuMapper.selectList(new LambdaQueryWrapper<ProductSku>()
                        .in(ProductSku::getId, skuIdList)
                        .select(ProductSku::getId,
                                ProductSku::getSalePrice))
                .stream()
                .map(productSku -> SkuPrice
                        .builder()
                        .marketPrice(productSku.getMarketPrice())
                        .salePrice(productSku.getSalePrice())
                        .skuId(productSku.getId())
                        .build()
                ).toList();
    }

    @Override
    public int updateStatus(Long id, Byte status) {
        //优化更新商品状态逻辑，在更新时同时更新sku表和库存表
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter("sku:bloom:filter");
        List<ProductSku> productSkus = productSkuMapper.selectList(new LambdaQueryWrapper<ProductSku>().eq(ProductSku::getProductId, id));
        productSkus.forEach((productSku) -> {
            productSku.setStatus(status);
            //sku加入布隆过滤器
            if (status == 1) bloomFilter.add(productSku.getId());
        });

        productSkuService.updateBatchById(productSkus);
        skuStockMapper.updateBatch(
                SkuStock.builder()
                        .status(status)
                        .updateBy(SecurityUtils.getUsername())
                        .updateTime(new Date())
                        .build(),
                productSkus.stream().map(
                                BaseEntity::getId)
                        .toList());
        return productMapper.updateById(Product.builder()
                .id(id)
                .status(status)
                .build());
    }
}
